import { Injectable, Inject, Scope } from '@nestjs/common';
import { In, IsNull, Not, Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { SysOperlogEntity } from './entities/operlog.entity';
import { REQUEST } from '@nestjs/core';
import { Request } from 'express';
import { ResultData } from 'src/common/utils/result';
import { AxiosService } from 'src/module/common/axios/axios.service';
import { ExportTable } from '../../../common/utils/export';

@Injectable({ scope: Scope.REQUEST })
export class OperlogService {
  constructor(
    @Inject(REQUEST)
    private readonly request: Request & { user: any },
    @InjectRepository(SysOperlogEntity)
    private readonly sysOperlogEntityRep: Repository<SysOperlogEntity>,
    private readonly axiosService: AxiosService,
  ) {}

  async findAll(query: any) {
    const entity = this.sysOperlogEntityRep.createQueryBuilder('entity');

    if (query.pageSize && query.pageNum) {
      entity.skip(query.pageSize * (query.pageNum - 1)).take(query.pageSize);
    }

    if (query.title) {
      entity.andWhere(`entity.title LIKE "%${query.title}%"`);
    }

    if (query.businessType) {
      entity.andWhere(`entity.businessType = :businessType`, { businessType: query.businessType });
    }

    if (query.operName) {
      entity.andWhere(`entity.operName LIKE "%${query.operName}%"`);
    }

    const orderMap = {
      descending: 'DESC',
      ascending: 'ASC',
    };

    if (query.orderByColumn && query.isAsc) {
      entity.orderBy(`entity.${query.orderByColumn}`, orderMap[query.isAsc]);
    }

    const [list, total] = await entity.getManyAndCount();

    return ResultData.ok({
      list,
      total,
    });
  }

  async removeAll() {
    await this.sysOperlogEntityRep.delete({ operId: Not(IsNull()) });
    return ResultData.ok();
  }

  async findOne(id: number) {
    const data = await this.sysOperlogEntityRep.findOne({ where: { operId: id } });
    return ResultData.ok(data);
  }

  async remove(ids: number[]) {
    const data = await this.sysOperlogEntityRep.delete({ operId: In(ids) });
    return ResultData.ok(data);
  }

  /**
   * @description: 录入日志
   */
  async logAction({ resultData, costTime, title, handlerName, errorMsg, businessType }: { resultData?: any; costTime: number; title: string; handlerName: string; errorMsg?: string; businessType: number }) {
    const { originalUrl, method, ip, body, query } = this.request;
    const { user } = this.request.user;
    const operLocation = await this.axiosService.getIpAddress(ip);

    const params = {
      title,
      method: handlerName,
      operName: user.nickName,
      deptName: user.deptName,
      operUrl: originalUrl,
      requestMethod: method.toUpperCase(),
      operIp: ip,
      costTime: costTime,
      operLocation: operLocation,
      operParam: JSON.stringify({ ...body, ...query }),
      jsonResult: JSON.stringify(resultData),
      errorMsg,
      businessType,
      operatorType: '1',
      operTime: new Date(),
      status: errorMsg ? '1' : '0',
    };

    await this.sysOperlogEntityRep.save(params);
  }

  /**
   * 导出操作日志数据为xlsx文件
   * @param res
   * @param body
   */
  async export(res: any, body: any) {
    delete body.pageNum;
    delete body.pageSize;
    const list = await this.findAll(body);
    const options = {
      sheetName: '操作日志数据',
      data: list.data.list,
      header: [
        { title: '日志序号', dataIndex: 'operId' },
        { title: '操作模块', dataIndex: 'title' },
        { title: '操作类型', dataIndex: 'method' },
        { title: '操作人员', dataIndex: 'operName' },
        { title: '操作部门', dataIndex: 'deptName' },
        { title: '操作地址', dataIndex: 'operLocation' },
        { title: '操作方法', dataIndex: 'operUrl' },
        { title: '请求方式', dataIndex: 'requestMethod' },
        { title: '操作时间', dataIndex: 'operTime' },
        { title: '操作状态', dataIndex: 'status' },
        { title: '操作参数', dataIndex: 'operParam' },
        { title: '返回参数', dataIndex: 'jsonResult' },
        { title: '操作耗时(ms)', dataIndex: 'costTime' },
      ],
    };
    return ExportTable(options, res);
  }
}
